package io.renren.modules.avanotes.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.renren.common.utils.BizUtils;
import io.renren.common.utils.PageUtils;
import io.renren.common.utils.Query;
import io.renren.common.utils.RedisKeys;
import io.renren.common.vo.LocalMarkdownNotesVo;
import io.renren.common.vo.TokenVo;
import io.renren.config.BizConfig;
import io.renren.modules.avanotes.dao.LocalMarkdownNotesDao;
import io.renren.modules.avanotes.dao.SynonymTokensDao;
import io.renren.modules.avanotes.entity.LocalMarkdownNotesEntity;
import io.renren.modules.avanotes.entity.SynonymTokensEntity;
import io.renren.modules.avanotes.service.LocalMarkdownNotesService;
import io.renren.modules.avanotes.service.TokenAnalyzerService;
import io.renren.modules.avanotes.service.TokenService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


//@Service("localMarkdownNotesService")//默认只有一个实现，那就不写名称了直接使用默认的名称！
@Service
public class LocalMarkdownNotesServiceImpl extends ServiceImpl<LocalMarkdownNotesDao, LocalMarkdownNotesEntity> implements LocalMarkdownNotesService {

    @Autowired
    @Qualifier(BizConfig.IMPL_TOKENIZER_INDEX)
    TokenService indexTokenService;

    @Autowired
    @Qualifier(BizConfig.IMPL_IK_ANALYZER_SMART)
    TokenAnalyzerService ikSmartService;

    @Autowired
    SynonymTokensDao stDao;


    public static final String[] columnArr = {LocalMarkdownNotesEntity.CN_ID, LocalMarkdownNotesEntity.CN_ABSOLUTE_PATH
            , LocalMarkdownNotesEntity.CN_FILE_NAME, LocalMarkdownNotesEntity.CN_STATUS, LocalMarkdownNotesEntity.CN_RELATIVE_PATH
            , LocalMarkdownNotesEntity.CN_UPDATE_TIME, LocalMarkdownNotesEntity.CN_CREATE_TIME};

    @Override
    public void insertIgnore(LocalMarkdownNotesEntity entity) {
        this.baseMapper.insertIgnore(entity);
    }

    @Override
    public void insertUpdate(LocalMarkdownNotesEntity entity) {
        this.baseMapper.insertUpdate(entity);
    }

    @Override
    public long insertNote(LocalMarkdownNotesEntity entity) {
        long res = 0;
        int count = this.count(new QueryWrapper<LocalMarkdownNotesEntity>().eq(LocalMarkdownNotesEntity.CN_MD5, entity.getMd5()));
        if (count == 0) {
            //如果没有相同内容的数据，执行 replace into
            this.insertUpdate(entity);
            res = entity.getId();
        }
        return res;
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        String key = (String) params.get("key");
        IPage<LocalMarkdownNotesEntity> page = this.page(
                new Query<LocalMarkdownNotesEntity>().getPage(params),
                new QueryWrapper<LocalMarkdownNotesEntity>().select(columnArr).like(StringUtils.isNotBlank(key), LocalMarkdownNotesEntity.CN_CONTENT, key)
        );

        //new QueryWrapper<ScheduleJobLogEntity>().like(StringUtils.isNotBlank(jobId),"job_id", jobId)
        return new PageUtils(page);
    }

    @Override
    public PageUtils searchPage(Map<String, Object> params) {
        String key = (String) params.get("key");
        IPage<LocalMarkdownNotesEntity> page;
        if (StringUtils.isBlank(key)) {
            page = this.page(
                    new Query<LocalMarkdownNotesEntity>().getPage(params),
                    new QueryWrapper<LocalMarkdownNotesEntity>().select(columnArr));
            return new PageUtils(page);
        } else {
            page = this.page(
                    new Query<LocalMarkdownNotesEntity>().getPage(params),
                    new QueryWrapper<LocalMarkdownNotesEntity>().like(LocalMarkdownNotesEntity.CN_CONTENT, key));
            List<LocalMarkdownNotesEntity> list = page.getRecords();
            List<LocalMarkdownNotesVo> voList = new ArrayList<>();
            for (LocalMarkdownNotesEntity entity : list) {
                LocalMarkdownNotesVo vo = new LocalMarkdownNotesVo();
                BeanUtils.copyProperties(entity, vo);
                //生成 keyDescription
                String rKey = RedisKeys.getIndexTokenKey(LocalMarkdownNotesEntity.TABLE_NAME, vo.getId() + "");

                List<Integer> ll = indexTokenService.searchTokenIndex(rKey, key);
                String content = entity.getContent();
                int len = content.length();
                int kLen = key.length();
                String kd = "";
                for (Integer index : ll) {
                    int begin = index - 3;
                    begin = begin < 0 ? 0 : begin;
                    int end = index + kLen + 3;
                    end = end > len ? len : end;
                    kd += content.substring(begin, end) + "...";
                }

                vo.setKeyDescription(kd);
                voList.add(vo);
            }

            PageUtils pageUtils = new PageUtils(page);
            pageUtils.setList(voList);
            return pageUtils;
        }


    }

    /**
     * 关键词的机械匹配
     *
     * @param params
     * @return
     */
    @Override
    public PageUtils keywordSearch(Map<String, Object> params) {
        String key = (String) params.get(BizConfig.SEARCH_KEY);
        QueryWrapper<LocalMarkdownNotesEntity> queryWrapper = new QueryWrapper<LocalMarkdownNotesEntity>().select(columnArr);
        boolean keyIfNotBlank = StringUtils.isNotBlank(key);
        queryWrapper.like(keyIfNotBlank, LocalMarkdownNotesEntity.CN_RELATIVE_PATH, key).or().like(keyIfNotBlank, LocalMarkdownNotesEntity.CN_CONTENT, key);
        IPage<LocalMarkdownNotesEntity> page = this.page(
                new Query<LocalMarkdownNotesEntity>().getPage(params),
                queryWrapper);
        return new PageUtils(page);
    }

    /**
     * 完全匹配关键字所在地方
     *
     * @param noteId
     * @param keyword
     * @return
     */
    @Override
    public String findKeywordDetail(Long noteId, String keyword) {
        String res = "";
        LocalMarkdownNotesEntity entity = this.getById(noteId);
        if (entity == null || StringUtils.isBlank(entity.getContent()) || StringUtils.isBlank(keyword)) {
            return res;
        }
        //完全匹配 Content 的内容
        String content = entity.getContent();
        //使用 index 无法判断，需要使用正则
        String keywordRegex = BizUtils.genRegexFromKey(keyword);
        //indexOf 无法满足需求
//        int beginIndex = content.indexOf(keyword);
//        if (beginIndex < 0) {
//            //没有匹配到
//            return res;
//        }
        Pattern compile = Pattern.compile(keywordRegex);
        Matcher matcher = compile.matcher(content);
        //boolean matches = Pattern.matches(keywordRegex, content);
        if (!matcher.find()) {
            //没有匹配到
            return res;
        }
//        Pattern compile = Pattern.compile(keywordPattern);
        res = BizUtils.genDetail(keyword, keywordRegex, content, 5, "...", "</br>", true);
        return res;
    }


    /**
     * 使用 MySQL 实现同义词搜索
     *
     * @param params
     * @return
     */
    @Override
    public PageUtils synonymSearch(Map<String, Object> params) throws IOException {
        String key = (String) params.get(BizConfig.SEARCH_KEY);
        if (StringUtils.isBlank(key)) {
            //变为普通关键词检索
            return keywordSearch(params);
        }
        //mysql: regex 的同义词检索
        QueryWrapper<LocalMarkdownNotesEntity> queryWrapper = new QueryWrapper<LocalMarkdownNotesEntity>().select(columnArr);
        List<TokenVo> voList = ikSmartService.token(key);
        if (CollectionUtils.isEmpty(voList)) {
            //变为普通关键词检索
            return keywordSearch(params);
        }
        //(实现)|(完成).{0,3}目标
        String regexStr = getRegexByTokens(key, voList);
        IPage<LocalMarkdownNotesEntity> simplePage = Query.getSimplePage(params);
        //new Page<LocalMarkdownNotesEntity>(curPage, limit)
        IPage<LocalMarkdownNotesEntity> pageByRegex = this.baseMapper.findPageByRegex(simplePage, regexStr);
        return new PageUtils(pageByRegex);
    }


    @Override
    public String findSynonymDetail(Long noteId, String word) throws IOException {
        String res = "";
        LocalMarkdownNotesEntity entity = this.getById(noteId);
        if (entity == null || StringUtils.isBlank(entity.getContent()) || StringUtils.isBlank(word)) {
            return res;
        }
        //从 word 生成 regex
        String regexByTokens = genRegexByKey(word);
        res = BizUtils.genDetailByRegex(entity.getContent(), regexByTokens, 5, "...", "</br>");
        return res;
    }


    /**
     * 实现目标
     *
     * @param key
     * @param voList
     * @return (实现)|(完成).{0,3}目标
     */
    private String getRegexByTokens(String key, List<TokenVo> voList) {
        StringBuilder sb = new StringBuilder();
        int len = voList.size();
        for (int i = 0; i < len; i++) {
            TokenVo token = voList.get(i);
            if (i == 0) {
                //第一个
                sb.append(key.substring(0, token.getBeginIndex()));
            }
            //查询集合
            List<SynonymTokensEntity> wordInSet = stDao.findWordInSet(token.getWord());
            if (CollectionUtils.isEmpty(wordInSet)) {
                //如果是空集合 —— 直接使用原来的
                sb.append(token.getWord());
            } else {
                sb.append("(");
                //如果存在其他
                for (SynonymTokensEntity item : wordInSet) {
                    //
                    String tokens = item.getTokens();
                    String[] splits = tokens.split(",");
                    for (int j = 0; j < splits.length; j++) {
                        //false
//                        sb.append("(").append(splits[j]).append(")");
                        sb.append(splits[j]);
                        if (j != splits.length - 1) {
                            sb.append("|");
                        }
                    }
                }
                sb.append(")");
            }
            if (i != len - 1) {
                sb.append(".{0,3}");
            }
        }
        return sb.toString();
    }

    /**
     * 通过搜索词返回同义词的正则表达式
     *
     * @param key
     * @return
     * @throws IOException
     */
    private String genRegexByKey(String key) throws IOException {
        List<TokenVo> voList = ikSmartService.token(key);
        if (CollectionUtils.isEmpty(voList)) {
            //返回原来的 key
            return key;
        }
        return getRegexByTokens(key, voList);
    }


}